﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Presentation.Events;
using Microsoft.Practices.Unity;

using Might.Core.DOM;
using Might.Infrastructure.DOM;
using Might.Infrastructure.Events;
using Might.Infrastructure.Services;

using Might.Core.SvnServiceFrontend;

namespace Might.Core.Services {

    ///<summary>
    ///</summary>
    public class SVNFileSystemService : IFileSystemService {

        private readonly IUnityContainer container;

        private IProgressToken progressToken;
        private SvnFileSystemRoot svnFileSystemRoot;
        private SvnFile svnFile;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="container"></param>
        /// <param name="eventAggregator"></param>
        public SVNFileSystemService() {
            this.container = CoreServices.Container;
            CoreServices.EventAggregator.GetEvent<OpenFileSystemRootEvent>().Subscribe(OpenFileSystemRootEventHandler, ThreadOption.UIThread, false);
            CoreServices.EventAggregator.GetEvent<OpenFileEvent>().Subscribe( OpenFileEventHandler , ThreadOption.UIThread , false );
        }


        ///<summary>
        /// odchytava udalosti typu OpenFileSystemRoot a testuje datovy naklad
        ///zda je typu ISVN
        ///pokud je otevere jej
        ///odesila udalosti o Progressu
        ///po skonceni odesle udalost OpenFileSystemRootFinished< IEventResult >
        ///ten kdo tohle odchtyva si data pretypu na napr. EventFileSystemRootResult
        ///</summary>
        ///<param name="fs"></param>
        public void OpenFileSystemRootEventHandler(IFileSystemRoot fs) {    
                        
            if (!(fs is SvnFileSystemRoot)) return;
        
            //SvnFileSystemRoot FS = (SvnFileSystemRoot)fs;
            svnFileSystemRoot = (SvnFileSystemRoot)fs;

            progressToken = container.Resolve<IProgressService>().ProgressCreate(typeof(OpenFileSystemRootEvent), svnFileSystemRoot);

            var svnClient = new SvnServiceClient();
            svnClient.Svn_ListCompleted += new EventHandler<Svn_ListCompletedEventArgs>(svnClient_Svn_ListCompletedRoot);

            svnClient.Svn_ListAsync(svnFileSystemRoot.Uri, svnFileSystemRoot.Username, svnFileSystemRoot.Password);
            progressToken.Progress(10, "Async svn list request finished.");
            
        }

        void svnClient_Svn_ListCompletedRoot(object sender, Svn_ListCompletedEventArgs e) {

            if (e.Error != null) {
                string error = "Svn list request error! Reason: " + e.Error.Message;
                progressToken.ProgressEnd(ProgressResult.Fail, error);
                return;
            }

            progressToken.Progress(50, "Svn list obtained successfully");
            
            int i = 1;
            
            foreach (string file in e.Result){
                SvnFile svnfile = new SvnFile( file.EndsWith( "/" ) );
                svnfile.FileSystem = svnFileSystemRoot;
                svnfile.Name = file;
                svnfile.Parent = svnFileSystemRoot;
                if (svnFileSystemRoot.Uri.EndsWith("/")) {
                    svnfile.Uri = svnFileSystemRoot.Uri + file;
                }
                else {
                    svnfile.Uri = svnFileSystemRoot.Uri + "/" + file;
                }

                //TODO : predelat !!!!
                /*
                bool isChildren = false;  // TODO tohle je prozatimni, bude tu verzova a checkoutova kontrola
                foreach (SvnFile f in svnFileSystemRoot.Children) {
                    if (f.Name.Equals(file)) {
                        isChildren = true;
                        break;
                    }
                }
                if (isChildren == false) {
                    svnFileSystemRoot.InsertChild( svnfile );
                }*/
                svnFileSystemRoot.InsertChild( GroupNames.File , svnfile );

                progressToken.Progress(50 + i*(50 / e.Result.Count), "File " + file + " added successfully");
                i++;

            }
            
            progressToken.ProgressEnd(ProgressResult.Success, "Svn list request finished");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fs"></param>
        public void OpenFileEventHandler(IFile fs) {
            if (!(fs is SvnFile)) return;
            svnFile = (SvnFile)fs;

            progressToken = container.Resolve<IProgressService>().ProgressCreate(typeof(OpenFileEvent), svnFile);
            
            var svnClient = new SvnServiceClient();
            svnClient.Svn_ListCompleted +=new EventHandler<Svn_ListCompletedEventArgs>(svnClient_Svn_ListCompleted);
            svnClient.GetFileCompleted +=new EventHandler<GetFileCompletedEventArgs>(svnClient_GetFileCompleted);

            if (svnFile.IsDir) {                
                                
                svnClient.Svn_ListAsync(svnFile.Uri,((SvnFileSystemRoot)svnFile.FileSystem).Username,((SvnFileSystemRoot)svnFile.FileSystem).Password);
                progressToken.Progress(10, "Async svn list request finished.");
                
                // ==> create and put files in dir into fs.children, based on data saved on server
                // this fires obser. collection changed event, for FS browser and other listeners
            } else {
                // ==> load file content, based on data saved on server
                // this should be recognized by AST parser...

                UserInfo ui = (UserInfo)((SvnFileSystemRoot)svnFile.FileSystem).Parent;
                svnClient.GetFileAsync(svnFile.Uri, ((SvnFileSystemRoot)svnFile.FileSystem).Username, ((SvnFileSystemRoot)svnFile.FileSystem).Password, ui.Name, FileMode.Open, FileAccess.Read);
                progressToken.Progress(10, "Async request for file handle finished.");

//                svnFile.Data = new FileStream(fs.Name, FileMode.Open, FileAccess.Read);
            }

            //t.ProgressEnd(ProgressResult.Success, "Load SV file finished");*/
        }

        void svnClient_GetFileCompleted(object sender, GetFileCompletedEventArgs e) {

            if (e.Error != null) {
                string error = "Svn file handle error! Reason: " + e.Error.Message;
                progressToken.ProgressEnd(ProgressResult.Fail, error);
                return;
            }

            progressToken.Progress(50, "File handle obtained succesfully");

            svnFile.Data = new MemoryStream(e.Result);
            progressToken.ProgressEnd(ProgressResult.Success, "Load SV file finished");

        }

        void svnClient_Svn_ListCompleted(object sender, Svn_ListCompletedEventArgs e) {
            
            if (e.Error != null) {
                string error = "Svn list request error! Reason: " + e.Error.Message;
                progressToken.ProgressEnd(ProgressResult.Fail, error);
                return;
            }

            progressToken.Progress(50, "Svn list obtained successfully");

            int i = 1;

            foreach (string file in e.Result) {
                SvnFile svnfile = new SvnFile( file.EndsWith( "/" ) );
                svnfile.FileSystem = svnFile.FileSystem;
                svnfile.Name = file;                
                svnfile.Parent = svnFile;
                svnfile.Uri = svnFile.Uri + file;                
                 
                 //TODO : predelat !!!!
                /*
                bool isChildren = false;  // TODO tohle je prozatimni, bude tu verzova a checkoutova kontrola
                foreach (SvnFile f in svnFile.Children) {
                    if (f.Name.Equals(file)) {
                        isChildren = true;
                        break;
                    }
                }
                if (isChildren == false) {                                        
                    svnFile.Children.Add(svnfile);
                } */

                this.svnFile.InsertChild( GroupNames.File , svnfile );
                                 

                progressToken.Progress(50 + i * (50 / e.Result.Count), "File " + file + " added successfully");
                i++;

            }

            progressToken.ProgressEnd(ProgressResult.Success, "Svn list request finished");
        }

    }
}
